package com.distribute.framework.core.apt;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLClassLoader;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import com.distribute.framework.core.sql.Column;
import com.distribute.framework.core.sql.Lazy3qDaoSupport;
import com.distribute.framework.core.sql.Table;
import com.distribute.framework.core.web.helper.Utils;
import com.distribute.framework.core.web.helper.FileHelper;


@SuppressWarnings({"unchecked","unused","static-access", "serial"})
public class Engine{	
	public static String javac="\"D:\\Program Files\\Java\\jdk1.7.0_79\\bin\\javac.exe\"";
	public static String root="";
	public static String work="work";
	
	public static String execute(String template,String filename,Map<String,Object> params)throws RemoteException,Exception
	{
		Class cls = getTplService(template);
		TplBase tpl=(TplBase) (cls.newInstance());
		tpl.setFilename(filename);
		tpl.execute(new BaseIO(),params);
		String outputString = tpl.out==null?null:tpl.out.getContent();
		nullInstance(tpl);
		tpl=null;
		new File(root + "work/apt/"+getJavaClassString(template)+".java").delete();
		new File(root + "work/apt/"+getJavaClassString(template)+".class").delete();
		new File(root + "work/apt").delete();
		new File(root + "work").delete();
		return outputString;
	}
	
	public static String execute(String template,Map<String,Object> params)throws RemoteException,Exception
	{
		Class cls = getTplService(template);
		TplBase tpl=(TplBase) (cls.newInstance());
		tpl.execute(new BaseIO(),params);
		String outputString = tpl.out==null?null:tpl.out.getContent();
		nullInstance(tpl);
		tpl=null;
		new File(root + "work/apt/"+getJavaClassString(template)+".java").delete();
		new File(root + "work/apt/"+getJavaClassString(template)+".class").delete();
		new File(root + "work/apt").delete();
		new File(root + "work").delete();
		return outputString;
	}
	
	public static void nullInstance(Object instance)
	{
	    if (instance == null) {
	      return;
	    }
	    Field[] fields = instance.getClass().getDeclaredFields();
	    for (int i = 0; i < fields.length; ++i) {
	      Field field = fields[i];
	      int mods = field.getModifiers();
	      if (field.getType().isPrimitive()) continue; if (field.getName().indexOf("$") != -1) {
	        continue;
	      }
	      try
	      {
	        field.setAccessible(true);
	        if ((!Modifier.isStatic(mods)) || (!Modifier.isFinal(mods)))
	        {
	          Object value = field.get(instance);
	          if (null != value) {
	            Class valueClass = value.getClass();
	            field.set(instance, null);
	          }
	        }
	      }
	      catch (Throwable t)
	      {
	        t.printStackTrace();
	      }
	    }
	 }

	
	public static Class getTplService(String template)throws Exception {		
		CreateJava(template);
		Compile(template);
		String className = getJavaClassString(template);
		URLClassLoader classLoader = new URLClassLoader(new URL[] { new URL(
				"file:" + new File(root + "work/").getAbsolutePath().replace("\\", "/")+"/") }, Thread
				.currentThread().getContextClassLoader());
		Class clazz = classLoader.loadClass("apt."+className);
		return clazz;
	}
	
	/**
	 * 编译类
	 * @param project
	 * @param template
	 * @throws Exception
	 */
	public static void Compile(String template)throws Exception
	{
		//对应的类名
		String className=getJavaClassString(template);
		//获取对应的java文件
		String filePath=className.replaceAll("\\.", "/");
		
		//java文件是否存在
		File javaFile=new File(root+work+"/apt/"+className+".java");
		//class文件是否存在
		File classFile=new File(root+work+"/apt/"+className+".class");
		
		String libPath=new File(root+"lib/lazy3q.3.1.jar").getAbsolutePath();
		//System.out.println(libPath);
		//如果java文件不存在，或者java文件的最后时间和模板文件不一样，则创建一个java文件
		if(!classFile.exists() || classFile.lastModified()!=javaFile.lastModified()){			
			String strOrder=javac+" -encoding UTF-8 -classpath "+libPath+" "+new File(root+work+"/apt/"+className+".java").getAbsolutePath();
			final Process process = Runtime.getRuntime().exec(strOrder);			
			InputStream input = process.getErrorStream();
			BufferedReader reader=new BufferedReader(new InputStreamReader(input));
			String strLine=null;
			while((strLine=reader.readLine())!=null)
				System.out.println(strLine);			
			classFile.setLastModified(javaFile.lastModified());
		}
	}
	
	
	
	/**
	 * 创建
	 */
	public static Boolean CreateJava(String template)throws Exception
	{
		//如果java文件不丰存在，或者java文件最后修改时间跟模版时间不一样，则创建java
		//对应的类名
		String className=getJavaClassString(template);
		
		File templateFile=new File(template);
		//java文件是否存在
		File javaFile=new File(root + work + "/apt/"+className+".java");
		//System.out.println(javaFile.getAbsolutePath());
		
		//如果java文件不存在，或者java文件的最后时间和模板文件不一样，则创建一个java文件
		//if(!javaFile.exists() || javaFile.lastModified()!=templateFile.lastModified()){
			//System.out.println("创建java文件 - "+className);
			String javaCode=GetJavaCode(template,className);
			WrteFile(root + work + "/apt/"+className+".java", javaCode, "UTF-8");			
			javaFile.setLastModified(templateFile.lastModified());
			return true;
//		}else{
//			return false;
//		}
	}
	
	protected static void WrteFile(String fileName,String content,String encode)
	{
		if(encode==null)
			encode="UTF-8";
		try{
			fileName=fileName.replace("/", "\\");
			fileName=fileName.replace("\\\\", "\\");
			
			String filePath=fileName.substring(0,fileName.lastIndexOf("\\"));
			
			if(!new File(filePath).exists())
				new File(filePath).mkdirs();
			
			FileOutputStream fos = new FileOutputStream(new File(fileName));
			Writer out = new OutputStreamWriter(fos,encode);
			out.write(content);
			out.close();
		} catch (IOException ex) {			
			System.out.println("写文件["+fileName+"]到["+fileName+"]时出错:"+ex.getMessage());
			ex.printStackTrace();
		}
	}

	public static String getJavaClassString(String src)
	{
		return "t_"+Utils.md5(src);
	}
	
	public static String GetJavaCode(String template, String className) throws Exception
	{
		String encode=FileHelper.getCharset(new FileInputStream(template));
		InputStream input = new FileInputStream(template);
		BufferedReader reader=new BufferedReader(new InputStreamReader(input,encode));
		String fileString="";
		String strLine=null;
		while((strLine=reader.readLine())!=null)
			fileString+=strLine+"\n";
		fileString=fileString.replaceAll("(?=\\n)[\\s]*?(<"+"#[^>]*#"+">)[\\s]*?(?=\\n)", "$1");//去除# >与< #之前的空白
		return CreateJavaCode(className,fileString);
	}
	
	
	
	public final static int STRING=0;
	public final static int CODE=1;
	public final static int INCLUDE=2;
	public final static int IMPORT=3;
	public final static int FUNCTION=4;
	public final static int PRINTAT=5;
	public final static int FILENAME=6;
	public final static int FOLLOW=7;
	public final static int BEGIN=8;
	public final static int END=9;
	public static String CreateJavaCode(String className,String fileString){
		List<Segment> segments=SyntaxAnalysis(fileString);
		List<StringBuffer> codes = new ArrayList();
		String imports="";	
		String follows="";

		imports+="import com.distribute.framework.core.apt.TplBase;\n";
		imports+="import com.distribute.framework.core.apt.BaseIO;\n";
		imports+="import java.util.Map;\n";

		int follow=0;
		int index = 0;
		codes.add(new StringBuffer());

		for(int i=0;i<segments.size();i++)
		{
			Segment seq=segments.get(i);
			int type=seq.type;
			String  value=seq.value;

			switch(type){
			case STRING:
				value = value.replace("\r\n", "\n");
				value = value.replace("\\", "\\\\");
				value = value.replace("\n", "\\n");
				value = value.replace("\"", "\\\"");
				codes.get(index).append("		out.print(\""+value+"\");\n");
				break;
			case CODE:
				codes.get(index).append(BlankCode(value,"		")+"\n");
				break;
			case FUNCTION:
				if(value.equals("}")){
					codes.get(index).append(BlankCode(value,"	")+"\n");
					index = 0;
				}else{
					index = codes.size();	
					codes.add(new StringBuffer());
					codes.get(index).append(BlankCode(value,"	")+"\n");
				}
				break;
			case IMPORT:
				{
					value = value.replace(" ", "");
					String[] arrays=value.split(";");
					for(int j=0;j<arrays.length;j++)
						imports+="import "+arrays[j]+";\n";
				}			
				break;
			case PRINTAT:
				codes.get(index).append("		out.print("+value+");\n");	
				break;
			case FILENAME:
				codes.get(index).append("		this.setFilename("+value+");\n");
				codes.get(index).append("		out.setIndex(0);\n");
				break;
			case FOLLOW:
				{
					String strFollow=""+(++follow);
					follows+="	public void $"+strFollow+"_follow(String follow)\n";
					follows+="	{\n";		
					follows+=BlankCode(value,"		")+"\n";
					follows+="	}\n\n";
					codes.get(index).append("		out.setIndex("+strFollow+");\n");				
				}
				break;
			case BEGIN://替换开始
			{
				codes.get(index).append("		if(!empty(define("+value+"))){\n");
				codes.get(index).append("		out.print(define("+value+").trim());\n");
				codes.get(index).append("		}else{\n");
			}
			break;
			case END://替换结束
			{
				codes.get(index).append("		}\n");				
			}
			break;
			default:
				break;
			}		
		}

		String classString="package apt;\n\n";
				
		classString+=imports;
		
		classString+="\n";
		
		classString+="public class "+className.substring(className.lastIndexOf('.')+1)+" extends TplBase\n";
		classString+="{\n";
		for(int i=1;i<codes.size();i++)
			classString+=codes.get(i);
		classString+="\n";	
		classString+=follows;
		classString+="	public void execute(BaseIO io,Map<String,Object> params)\n";
		classString+="	{\n";
		classString+="		this.setParams(params);\n";
		classString+="		this.setIo(io);\n";
		classString+=codes.get(0);
		classString+="		this.complete();\n";
		classString+="	}\n";
		classString+="}\n";
		
		
		return classString;
	}
	private static String BlankCode(String src, String blank) {
		return blank+src.replace("\n", "\n"+blank);
	}
	
	
	
	/**
     * @notes 字符串转化为十六进制字符串
     * @param bytes
     * @return String
     */
    public static String hex(String strString) {
    	if(Utils.empty(strString))
    		return "";
    	StringBuffer strHex = new StringBuffer();  
    	for(int i=0;i<strString.length();i++){
    		Integer charCode = new Integer(strString.charAt(i));//取unicode码
    		charCode = charCode+23; //unicode码变种
    		strHex.append(Utils.zerofill(charCode.toString(charCode, 16), 4));////转成十六进制,4位对齐	
    	}
        return strHex.toString().toUpperCase();
    }
		
    
    public static class Parter
    {
    	public String before;
    	public String finder;
    	public String after;
    	public int index;

    	public Parter Find(String src,String find){			
    		before=null;
    		after=null;
    		finder=null;
    		index=-1;
    		if(src==null)
    			return this;
    		finder=find;
    		index=src.indexOf(find);
    		if(index==-1){
    			before=src;
    			return this;
    		}
    		before=src.substring(0,index);		
    		after=src.substring(index+find.length());
    		return this;
    	}
    }


	
	private static List<Segment> SyntaxAnalysis(String content) {
		List<Segment> segments=new ArrayList();
		if(content==null || content.trim().equals(""))
			return segments;
		Parter sf=new Parter();
		while(sf.Find(content,"<"+"#").index!=-1)
		{
			Boolean bFeed=false;//是否开始符之前有换行符		
			if(sf.before!=""){
				Segment seq=new Segment();
				seq.type=STRING;
				seq.value=sf.before;
				segments.add(seq);
			}
			content=sf.after;
			if(content=="")//未结束的 # >
				return segments;
			int code_type=0;
			char t=content.charAt(0);
			if(t==' ')
			{
				code_type=CODE;
				content=content.substring(1);
			}
			else if(t=='@')
			{
				code_type=IMPORT;
				content=content.substring(1);
			}
			else if(t=='!')
			{
				code_type=FUNCTION;
				content=content.substring(1);
			}
			else if(t=='=')
			{
				code_type=PRINTAT;
				content=content.substring(1);
			}
			else if(t=='&')//写入到的文件名
			{
				code_type=FILENAME;
				content=content.substring(1);
			}
			else if(t=='%')//部分内容操作
			{
				code_type=FOLLOW;
				content=content.substring(1);
			}
			else if(t=='^')//替换开始
			{
				code_type=BEGIN;
				content=content.substring(1);
			}
			else if(t=='$')//替换结束
			{
				code_type=END;
				content=content.substring(1);
			}
			else
				code_type=CODE;			
			
			if(sf.Find(content, "#"+">").index==-1)//未结束的 # >
			{			
				return segments;
			}
			
			if(sf.before!="")
			{
				Segment seq=new Segment();
				seq.type=code_type;
				seq.value=sf.before;
				segments.add(seq);
			}
			
			content=sf.after;
		}

		if(sf.before!="")
		{
			Segment seq=new Segment();
			seq.type=STRING;
			seq.value=sf.before;
			segments.add(seq);
		}
		return segments;
	}
	public static class Segment{
		public int type;
		public String value;
	}
	

	
}